/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/
const PENDING = 'pending' 
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise{
    constructor(fn) {
        try{
            fn(this.resolve, this.reject)
        } catch (error){
            this.reject(error)
        }
        
    }
    status = PENDING
    value = undefined
    reason = undefined
    fulfilledCallBack = []
    rejectedCallBack = []
    resolve = (value)=> {
        if(this.status ===PENDING){
            this.status = FULFILLED
            this.value = value
            while(this.fulfilledCallBack.length) this.fulfilledCallBack.shift()()
        }
    }
    reject = (reason)=> {
        if(this.status ===PENDING){
            this.status = REJECTED
            this.reason = reason
            while(this.rejectedCallBack.length) this.rejectedCallBack.shift()()
        }
    }
    then = (fulfilled, rejected)=> {
        fulfilled = fulfilled ? fulfilled: value => value
        rejected = rejected ? rejected: reason => reason
        const  MyPromise2 = new MyPromise((resolve, reject)=> {
            if(this.status === FULFILLED){
                    // setTimeout 是为了判断不能返回自己的时候，获取到自已，才异步调用
                    setTimeout(()=> {
                        try{
                            const x = fulfilled(this.value)
                            resolvePromise(MyPromise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    } ,0)
               
            } else if(this.status === REJECTED){
                    setTimeout(()=> {
                        try{
                            const x = rejected(this.reason)
                            resolvePromise(MyPromise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    } ,0)
                
            } else {
                try{
                    this.fulfilledCallBack.push(()=>{
                        setTimeout(()=> {
                            try{
                                const x = fulfilled(this.value)
                                resolvePromise(MyPromise2, x, resolve, reject)
                            } catch (e) {
                                reject(e)
                            }
                        } ,0)
                    })
                    this.rejectedCallBack.push(()=>{
                        setTimeout(()=> {
                            try{
                                const x = rejected(this.reason)
                                resolvePromise(MyPromise2, x, resolve, reject)
                            } catch (e) {
                                reject(e)
                            }
                        } ,0)
                    })
                }catch(e){
                    reject(e)
                }
                
            }
        })
        return MyPromise2
    }
    static all = (arrary)=> {
        return new MyPromise((resolve, reject)=> {
            const result = []
            let index = 0
            const addData = (key, value)=> {
                result[key] = value
                index++
                if(index === arrary.length){
                    resolve(result)
                }
            }
            for(let i=0; i<arrary.length; i++){
                const fn = arrary[i]
                if(fn instanceof MyPromise){
                    fn.then(value=> addData(i, value), reason=> reject(reason))
                    
                } else {
                    addData(i, fn)
                }
            }
        })
    }
    finally = (fn)=> {
        // finally 后边可以调用then,并且调用的then的value是上一个promise的执行结果，finally作为对象的方法被调用时，this是指向上一个promise的，所以里面then其实是上一个pomise的then
        // finally 需要保证fn执行之后，再去执行调用finally的promise，当异步时，使用resolve保证fn先执行，在去return value
       return this.then(value=> MyPromise.resolve(fn()).then(()=>{return value}), reason=> MyPromise.resolve(fn()).then(()=> reason))
    }
    catch = fn => this.then(undefined, fn)
    static resolve  = (value)=> {
        if(value instanceof MyPromise) return value
        return new MyPromise((resolve)=> {
            resolve(value)
        })
    }
}
function resolvePromise(MyPromise2, x, resolve, reject) {
    if(MyPromise2 === x){
        reject(new TypeError('不能返回自己！！！！！！！！！'))
        return
    }
    if(x instanceof MyPromise){
        x.then(resolve, reject)
    } else {
        resolve(x)
    }
}
module.exports = MyPromise